﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UvsChess;

namespace StudentAI
{
    public class MoveGeneration
    {
        static public List<ChessMove> getAllMoves( ChessBoard board, ChessColor color ) {
            List<ChessMove> moves = new List<ChessMove>();
            
            for (int y = 0; y < ChessBoard.NumberOfRows; y++) {
                for (int x = 0; x < ChessBoard.NumberOfColumns; x++) {
                    ChessPiece fromPiece = board[x, y];
                    ChessLocation fromLocation = new ChessLocation(x,y);
                    if (MoveValidation.SameColor(fromPiece, color))
                    {
                        switch (fromPiece)
                        {
                            case ChessPiece.Empty:
                                //Do Nothing, Shouldn't get here
                                break;
                            case ChessPiece.BlackBishop:
                            case ChessPiece.WhiteBishop:
                                moves.InsertRange(moves.Count(),generateBishopMoves(board, fromLocation, color));
                                break;
                            case ChessPiece.BlackKing:
                            case ChessPiece.WhiteKing:
                                moves.InsertRange(moves.Count(),generateKingMoves(board, fromLocation, color));
                                break;
                            case ChessPiece.BlackKnight:
                            case ChessPiece.WhiteKnight:
                                moves.InsertRange(moves.Count(),generateKnightMoves(board, fromLocation, color));
                                break;
                            case ChessPiece.BlackPawn:
                            case ChessPiece.WhitePawn:
                                moves.InsertRange(moves.Count(),generatePawnMoves(board, fromLocation, color));
                                break;
                            case ChessPiece.BlackQueen:
                            case ChessPiece.WhiteQueen:
                                moves.InsertRange(moves.Count(),generateQueenMoves(board, fromLocation, color));
                                break;
                            case ChessPiece.BlackRook:
                            case ChessPiece.WhiteRook:
                                moves.InsertRange(moves.Count(),generateRookMoves(board, fromLocation, color));
                                break;
                            default:
                                //Do Nothing, Shouldn't get here
                                break;
                        }
                    }
                    else //If not same color
                    {
                        //Do Nothing
                    }
                }
            }//End Board Loop
            return moves;
        }


        static public bool hasAnyMove(ChessBoard board, ChessColor color)
        {
            
            for (int y = 0; y < ChessBoard.NumberOfRows; y++)
            {
                for (int x = 0; x < ChessBoard.NumberOfColumns; x++)
                {
                    ChessPiece fromPiece = board[x, y];
                    ChessLocation fromLocation = new ChessLocation(x, y);
                    if (MoveValidation.SameColor(fromPiece, color))
                    {
                        switch (fromPiece)
                        {
                            case ChessPiece.Empty:
                                //Do Nothing, Shouldn't get here
                                break;
                            case ChessPiece.BlackBishop:
                            case ChessPiece.WhiteBishop:
                                if (generateBishopMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackKing:
                            case ChessPiece.WhiteKing:
                                if (generateKingMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackKnight:
                            case ChessPiece.WhiteKnight:
                                if (generateKnightMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackPawn:
                            case ChessPiece.WhitePawn:
                                if (generatePawnMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackQueen:
                            case ChessPiece.WhiteQueen:
                                if (generateQueenMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            case ChessPiece.BlackRook:
                            case ChessPiece.WhiteRook:
                                if (generateRookMoves(board, fromLocation, color).Count > 0)
                                    return true;
                                break;
                            default:
                                //Do Nothing, Shouldn't get here
                                break;
                        }
                    }
                    else //If not same color
                    {
                        //Do Nothing
                    }
                }
            }//End Board Loop
            return false;
        }
        static public List<ChessMove> generatePawnMoves(ChessBoard board, ChessLocation pawnLocation, ChessColor color) 
        {
            List<ChessMove> pawnMoves = new List<ChessMove>();
            int startY;
            int forward;
            if (color == ChessColor.Black)
            {
                startY = 1;
                forward = 1;
            }
            else //White
            {
                startY = 6;
                forward = -1;
            }
            //If space ahead is empty, add forward move to list
            if (board[pawnLocation.X, pawnLocation.Y + forward] == ChessPiece.Empty) 
            { 
                pawnMoves.Add(new ChessMove( pawnLocation, 
                                             new ChessLocation(pawnLocation.X, 
                                                               pawnLocation.Y + forward)));
            }
            //If both spaces ahead are emtpy, and pawn in starting position, forward*2 to list
            if (pawnLocation.Y == startY &&
                board[pawnLocation.X, (pawnLocation.Y + forward)] == ChessPiece.Empty &&
                board[pawnLocation.X, (pawnLocation.Y + forward*2)] == ChessPiece.Empty) 
            {
                pawnMoves.Add(new ChessMove(pawnLocation,
                                             new ChessLocation(pawnLocation.X,
                                                               pawnLocation.Y + forward*2)));
            }
            //If not going off of board, and diagonal is an enemy piece, add Pawn Take move to list
            if (pawnLocation.X - 1 >= 0 &&
                isEnemyPiece(board[pawnLocation.X - 1, pawnLocation.Y + forward], color)) 
            {
                pawnMoves.Add(new ChessMove(pawnLocation,
                                            new ChessLocation(pawnLocation.X - 1,
                                                              pawnLocation.Y + forward)));
            }
            //If not going off of board, and diagonal is an enemy piece, add Pawn Take move to list
            if (pawnLocation.X + 1 <= 7 &&
                isEnemyPiece(board[pawnLocation.X + 1, pawnLocation.Y + forward], color))
            {
                pawnMoves.Add(new ChessMove(pawnLocation,
                                            new ChessLocation(pawnLocation.X - 1,
                                                              pawnLocation.Y + forward)));
            }
            return pawnMoves;
        }
        
        static public List<ChessMove> generateRookMoves(ChessBoard board, ChessLocation rookLocation, ChessColor color)
        {
            List<ChessMove> rookMoves = new List<ChessMove>();
            ChessPiece current;
            //Go in 4 directions
            //break loop if end of board or not empty
            //x+
            for (int x = rookLocation.X + 1; ; ++x) 
            {
                if (x > 7) break;
                current = board[x, rookLocation.Y];
                //If empty or enemy
                if (!MoveValidation.SameColor(current, color))
                {
                    rookMoves.Add(new ChessMove(rookLocation,
                                                new ChessLocation(x, rookLocation.Y)));
                    //If enemy
                    if (current != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(current, color))
                    break;
            }
            //x-
            for (int x = rookLocation.X - 1; ; --x)
            {
                if (x < 0) break;
                current = board[x, rookLocation.Y];
                //If empty or enemy
                if (!MoveValidation.SameColor(current, color))
                {
                    rookMoves.Add(new ChessMove(rookLocation,
                                                new ChessLocation(x, rookLocation.Y)));
                    //If enemy
                    if (current != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(current, color))
                    break;
                
            }
            //y+
            for (int y = rookLocation.Y + 1; ; ++y)
            {
                if (y > 7) break;
                current = board[rookLocation.X, y];
                //If empty or enemy
                if (!MoveValidation.SameColor(current, color))
                {
                    rookMoves.Add(new ChessMove(rookLocation,
                                                new ChessLocation(rookLocation.X, y)));
                    //If enemy
                    if (current != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(current, color))
                    break;
                
            }
            //y-
            for (int y = rookLocation.Y - 1; ; --y)
            {
                if (y < 0) break;
                current = board[rookLocation.X, y];
                //If empty or enemy
                if (!MoveValidation.SameColor(current, color))
                {
                    rookMoves.Add(new ChessMove(rookLocation,
                                                new ChessLocation(rookLocation.X, y)));
                    //If enemy
                    if (current != ChessPiece.Empty) break;
                }
                else if (MoveValidation.SameColor(current, color))
                    break;
                
            }
            return rookMoves;
        }
        
        static public List<ChessMove> generateBishopMoves(ChessBoard board, ChessLocation bishopLocation, ChessColor color)
        {
            List<ChessMove> bishopMoves = new List<ChessMove>();
            //Go in 4 directions
            int x, y;
            //x+ y+
            x = bishopLocation.X + 1;
            y = bishopLocation.Y + 1;
            for (; (x < ChessBoard.NumberOfColumns &&
                    y < ChessBoard.NumberOfRows); ++x, ++y) {
                        if (board[x, y] == ChessPiece.Empty) { 
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x,y)));
                        }
                        else if (!MoveValidation.SameColor(board[x, y], color)) {
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x, y)));
                            break;
                        }
                        else
                        {
                            break;
                        }
            }
            //x+ y-
            x = bishopLocation.X + 1;
            y = bishopLocation.Y - 1;
            for (; (x < ChessBoard.NumberOfColumns &&
                    y >= 0); ++x, --y) {
                        if (board[x, y] == ChessPiece.Empty ) { 
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x,y)));
                        }
                        else if (!MoveValidation.SameColor(board[x, y], color)) {
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x, y)));
                            break;
                        }
                        else {
                            break;
                        }
            }
            //x- y+
            x = bishopLocation.X - 1;
            y = bishopLocation.Y + 1;
            for (; (x >= 0 &&
                    y < ChessBoard.NumberOfRows); --x, ++y) {
                        if (board[x, y] == ChessPiece.Empty ) { 
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x,y)));
                        }
                        else if (!MoveValidation.SameColor(board[x, y], color)) {
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x, y)));
                            break;
                        }
                        else
                        {
                            break;
                        }
            }
            //x- y-
            x = bishopLocation.X - 1;
            y = bishopLocation.Y - 1;
            for (; (x >= 0 &&
                    y >= 0); --x, --y) {
                        if (board[x, y] == ChessPiece.Empty) { 
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x,y)));
                        }
                        else if (!MoveValidation.SameColor(board[x, y], color)) {
                            bishopMoves.Add(new ChessMove(bishopLocation, new ChessLocation(x, y)));
                            break;
                        }
                        else
                        {
                            break;
                        }
            }
            return bishopMoves;
        }

        static public List<ChessMove> generateKnightMoves(ChessBoard board, ChessLocation knightLocation, ChessColor color)
        {
            List<ChessMove> knightMoves = new List<ChessMove>();
            //Test 8 directions, make sure empty or enemy (!same)
            //Y + 2, X + 1
            if (knightLocation.Y + 2 <= 7 &&
                knightLocation.X + 1 <= 7 &&
                !MoveValidation.SameColor(board[knightLocation.X + 1, knightLocation.Y + 2], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X + 1, 
                                                                knightLocation.Y + 2)));
            }
            //Y + 2, X - 1
            if (knightLocation.Y + 2 <= 7 &&
                knightLocation.X - 1 >= 0 &&
                !MoveValidation.SameColor(board[knightLocation.X - 1, knightLocation.Y + 2], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X - 1,
                                                                knightLocation.Y + 2)));
            }
            //Y - 2, X + 1
            if (knightLocation.Y - 2 >= 0 &&
                knightLocation.X + 1 <= 7 &&
                !MoveValidation.SameColor(board[knightLocation.X + 1, knightLocation.Y - 2], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X + 1,
                                                                knightLocation.Y - 2)));
            }
            //Y - 2, X - 1
            if (knightLocation.Y - 2 >= 0 &&
                knightLocation.X - 1 >= 0 &&
                !MoveValidation.SameColor(board[knightLocation.X - 1, knightLocation.Y - 2], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X - 1,
                                                                knightLocation.Y - 2)));
            }
            //X + 2, Y + 1
            if (knightLocation.Y + 1 <= 7 &&
                knightLocation.X + 2 <= 7 &&
                !MoveValidation.SameColor(board[knightLocation.X + 2, knightLocation.Y + 1], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X + 2,
                                                                knightLocation.Y + 1)));
            }
            //X + 2, Y - 1
            if (knightLocation.Y - 1 >= 0 &&
                knightLocation.X + 2 <= 7 &&
                !MoveValidation.SameColor(board[knightLocation.X + 2, knightLocation.Y - 1], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X + 2,
                                                                knightLocation.Y - 1)));
            }
            //X - 2, Y + 1
            if (knightLocation.Y + 1 <= 7 &&
                knightLocation.X - 2 >= 0 &&
                !MoveValidation.SameColor(board[knightLocation.X - 2, knightLocation.Y + 1], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X - 2,
                                                                knightLocation.Y + 1)));
            }
            //X - 2, Y - 1
            if (knightLocation.Y - 1 >= 0 &&
                knightLocation.X - 2 >= 0 &&
                !MoveValidation.SameColor(board[knightLocation.X - 2, knightLocation.Y - 1], color))
            {
                knightMoves.Add(new ChessMove(knightLocation,
                                              new ChessLocation(knightLocation.X - 2,
                                                                knightLocation.Y - 1)));
            }
            return knightMoves;
        }
        
        static public List<ChessMove> generateQueenMoves(ChessBoard board, ChessLocation queenLocation, ChessColor color)
        {
            List<ChessMove> queenMoves = new List<ChessMove>();
            queenMoves.InsertRange(queenMoves.Count(), generateRookMoves(board, queenLocation, color));
            queenMoves.InsertRange(queenMoves.Count(), generateBishopMoves(board, queenLocation, color));
            return queenMoves;
        }
        
        static public List<ChessMove> generateKingMoves(ChessBoard board, ChessLocation kingLocation, ChessColor color)
        {
            List<ChessMove> kingMoves = new List<ChessMove>();
            //Check all 8 directions
            //Y + 1, X + 0
            if (kingLocation.Y + 1 <= 7 &&
                !MoveValidation.SameColor(board[kingLocation.X, kingLocation.Y + 1], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X,
                                                                kingLocation.Y + 1)));
            }
            //Y + 1, X + 1            
            if (kingLocation.Y + 1 <= 7 &&
                kingLocation.X + 1 <= 7 &&
                !MoveValidation.SameColor(board[kingLocation.X + 1, kingLocation.Y + 1], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X + 1,
                                                                kingLocation.Y + 1)));
            }
            //Y + 0, X + 1            
            if (kingLocation.X + 1 <= 7 &&
                !MoveValidation.SameColor(board[kingLocation.X + 1, kingLocation.Y], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X + 1,
                                                                kingLocation.Y)));
            }
            //Y - 1, X + 1            
            if (kingLocation.Y - 1 >= 0 &&
                kingLocation.X + 1 <= 7 &&
                !MoveValidation.SameColor(board[kingLocation.X + 1, kingLocation.Y - 1], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X + 1,
                                                                kingLocation.Y - 1)));
            }
            //Y - 1, X + 0            
            if (kingLocation.Y - 1 >= 0 &&
                !MoveValidation.SameColor(board[kingLocation.X, kingLocation.Y - 1], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X,
                                                                kingLocation.Y - 1)));
            }
            //Y - 1, X - 1            
            if (kingLocation.Y - 1 >= 0 &&
                kingLocation.X - 1 >= 0 &&
                !MoveValidation.SameColor(board[kingLocation.X - 1, kingLocation.Y - 1], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X - 1,
                                                                kingLocation.Y - 1)));
            }
            //Y + 0, X - 1            
            if (kingLocation.X - 1 >= 0 &&
                !MoveValidation.SameColor(board[kingLocation.X - 1, kingLocation.Y], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X - 1,
                                                                kingLocation.Y)));
            }
            //Y + 1, X - 1
            if (kingLocation.Y + 1 <= 7 &&
                kingLocation.X - 1 >= 0 &&
                !MoveValidation.SameColor(board[kingLocation.X - 1, kingLocation.Y + 1], color))
            {
                kingMoves.Add(new ChessMove(kingLocation,
                                              new ChessLocation(kingLocation.X - 1,
                                                                kingLocation.Y + 1)));
            }
            
            return kingMoves;
        }

        public static bool isEnemyPiece(ChessPiece piece, ChessColor color)
        {
            if (piece != ChessPiece.Empty)
            {
                if (piece < ChessPiece.Empty)
                {
                    if (color == ChessColor.Black) return false;
                }
                if (piece > ChessPiece.Empty)
                {
                    if (color == ChessColor.White) return false;
                }
            }
            return false;
        }

    }//End class MoveGeneration    
}
